package com.start.platform.core;

import com.alibaba.fastjson2.JSONObject;
import com.start.common.details.BaseUserDetails;
import com.start.common.entity.StartDicData;
import com.start.common.exceptions.StartBusException;
import com.start.common.tools.SpringContextTools;
import com.start.common.tools.UUIdTools;
import com.start.core.service.StartLogService;
import com.start.platform.core.entity.StartPlatformConfigEntity;
import com.start.platform.core.entity.StartPlatformFans;
import com.start.platform.core.entity.StartPlatformUserEntity;
import com.start.platform.core.event.GlobalStartPlatformUserEventDispatcher;
import com.start.platform.core.security.StartPlatformUserDetails;
import com.start.platform.core.service.StartPlatformFansService;
import com.start.platform.core.service.StartPlatformUserService;
import com.start.platform.core.vo.StartPlatformFansDetail;
import com.start.platform.core.vo.StartPlatformUserLoginModel;
import com.start.security.StartTokenTools;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;


@Slf4j
public class StartPlatformManage {
    private ConcurrentHashMap<String, StartBasePlatformService> map = new ConcurrentHashMap<>();

    private static final StartPlatformManage manager = new StartPlatformManage();
    private StartTokenTools startTokenTools;

    private StartPlatformUserService startPlatformUserService;
    private StartPlatformFansService startPlatformFansService;

    private StartLogService startLogService;

    private boolean isInit = false;

    public static StartPlatformManage getInstance() {
        if (manager.isInit)
            return manager;
        synchronized (StartPlatformManage.class) {
            if (manager.isInit) {
                return manager;
            }
            manager.init();
            manager.isInit = true;
            return manager;
        }
    }

    protected void init() {
        startTokenTools = SpringContextTools.getBean(StartTokenTools.class);
        startPlatformUserService = SpringContextTools.getBean(StartPlatformUserService.class);
        startPlatformFansService = SpringContextTools.getBean(StartPlatformFansService.class);
        startLogService = SpringContextTools.getBean(StartLogService.class);
        Map<String, StartBasePlatformService> beans = SpringContextTools.getBeans(StartBasePlatformService.class, false);
        if (beans == null || beans.isEmpty()) return;
        for (StartBasePlatformService platform : beans.values()) {
            String platformType = platform.getPlatformType();
            if (StringUtils.isEmpty(platformType)) {
                log.error(platform.getClass().getName() + " 未指定平台类型。");
                continue;
            }
            if (map.containsKey(platformType)) {
                log.error("找到多个相同平台处理实例：" + platformType + "\n" + map.get(platformType).getClass() + "," + platform.getClass());
                continue;
            }
            map.put(platformType, platform);
        }
    }

    public void add(String platformType, StartPlatformConfigEntity entity) {
        StartBasePlatformService platformService = getPlatformService(platformType);
        platformService.add(entity);
    }

    public void update(String platformType, StartPlatformConfigEntity entity) {
        StartBasePlatformService platformService = getPlatformService(platformType);
        if (!platformService.hasAppId(entity.getAppId())) {
            throw new RuntimeException("未在" + platformType + "平台中找到appId为：" + entity.getAppId() + "的配置");
        }
        platformService.add(entity);
    }

    public void remove(String platformType, String appId) {
        StartBasePlatformService platformService = getPlatformService(platformType, false);
        if (!platformService.hasAppId(appId)) {
            return;
        }
        platformService.remove(appId);
    }


    public boolean hasPlatform(String platformType, String appId) {
        try {
            StartBasePlatformService platformService = getPlatformService(platformType);
            if (StringUtils.isNotEmpty(appId)) {
                return platformService.hasAppId(appId);
            }
            return true;

        } catch (Exception e) {
            return false;
        }

    }

    /**
     * 保存fans信息并绑定当前账号
     *
     * @param platformType
     * @param appId
     * @param autoBind
     * @param fans
     */
    public void saveFansAndBind(String platformType, String appId, boolean autoBind, StartPlatformFansDetail fans) {
        saveFans(platformType, appId, fans);
        if (!autoBind) {
            return;
        }
        BaseUserDetails currentUser = StartTokenTools.getCurrentUser(false);
        if (currentUser == null) {
            throw new StartBusException("用户未登录");
        }
        bindOtherPlatform(currentUser, platformType, appId, fans.getPlatformOpenId());
    }

    /**
     * 保存粉丝信息
     *
     * @param platformType
     * @param appId
     * @param fans
     */
    public StartPlatformFansDetail saveFans(String platformType, String appId, StartPlatformFansDetail fans) {
        if (StringUtils.isAllBlank(platformType)) {
            throw new StartBusException("平台类型不能为空");
        }
        if (StringUtils.isAllBlank(appId)) {
            throw new StartBusException("平台appId不能为空");
        }
        if (StringUtils.isAllBlank(fans.getPlatformOpenId())) {
            throw new StartBusException("用户唯一凭证id不能为空");
        }
        fans.setPlatformType(platformType);
        fans.setPlatformAppId(appId);
        StartPlatformFans user = startPlatformFansService.getFansByOpenId(fans.getPlatformType(), fans.getPlatformAppId(), fans.getPlatformOpenId());
        if (user != null) {
            fans.setId(user.getId());
            fans.setPlatformUserId(user.getPlatformUserId());
        } else {
            fans.setNewUser(true);
        }
        startPlatformFansService.saveOrUpdate(fans);
        return fans;
    }


    /**
     * 用户登录
     *
     * @param platformType
     * @param appId
     * @param code
     * @param prop
     * @return
     */
    public String login(String platformType, String appId, String code, JSONObject prop) {
        StartBasePlatformService platformService = getPlatformService(platformType);
        if (!platformService.hasAppId(appId)) {
            throw new RuntimeException("未在" + platformType + "平台中找到appId为：" + appId + "的配置");
        }
        StartPlatformFansDetail detail = platformService.getUserInfoByPlatformCode(appId, code, prop);
        StartPlatformUserEntity userEntity = getUserByFansDetail(detail);
        return login(userEntity, null);
    }

    private StartPlatformUserEntity getUserByFansDetail(StartPlatformFansDetail fansDetail) {
        StartPlatformUserEntity userEntity;
        if (StringUtils.isNotBlank(fansDetail.getPlatformUserId())) {
            return startPlatformUserService.getById(fansDetail.getPlatformUserId());
        }
        userEntity = new StartPlatformUserEntity();
        userEntity.setLastLoginTime(LocalDateTime.now());
        userEntity.setSelfModifyState(0);
        userEntity.setAvatar(fansDetail.getAvatar());
        userEntity.setRealName(fansDetail.getNickName());
        userEntity.setNickName(fansDetail.getNickName());
        userEntity.setUserName(fansDetail.getPlatformType() + "_" + UUIdTools.createSnowFakeId());
        userEntity.setLastLoginTime(LocalDateTime.now());
        GlobalStartPlatformUserEventDispatcher.getInstance().userRegisterBefore(fansDetail);
        startPlatformUserService.save(userEntity);
        GlobalStartPlatformUserEventDispatcher.getInstance().userRegisterAfter(fansDetail);
        return userEntity;
    }

    /**
     * 注册或登录
     *
     * @param platformType       平台类型
     * @param appId              appId
     * @param platformFansDetail
     * @return
     */
    public String saveFansAndLogin(String platformType, String appId, StartPlatformFansDetail platformFansDetail) {
        platformFansDetail = saveFans(platformType, appId, platformFansDetail);
        if (StringUtils.isNotBlank(platformFansDetail.getPlatformUserId())) {
            StartPlatformUserEntity userEntity = startPlatformUserService.getById(platformFansDetail.getPlatformUserId());
            return login(userEntity);
        }
        StartPlatformUserEntity userEntity = getUserByFansDetail(platformFansDetail);
        platformFansDetail.setPlatformUserId(userEntity.getId());
        platformFansDetail.setPlatformLastLoginTime(LocalDateTime.now());
        startPlatformFansService.save(platformFansDetail);
        return login(userEntity);
    }

    /**
     * 用户登录 （请注意该登录没有对用户密码进行验证）
     *
     * @param entity
     * @return
     */
    public String login(StartPlatformUserEntity entity) {
        return login(entity, null);
    }

    public String login(StartPlatformUserEntity entity, String pwd) {
        StartPlatformUserDetails userDetails = new StartPlatformUserDetails(entity);
        String login = startTokenTools.login(userDetails, pwd);
        startLogService.createUserLoginLog(userDetails);
        GlobalStartPlatformUserEventDispatcher.getInstance().userLoginAfter(entity);
        return login;
    }

    /**
     * 查询全部平台
     *
     * @return
     */
    public List<StartDicData> getAllPlatformType() {
        Enumeration<String> keys = map.keys();
        List<StartDicData> list = new ArrayList<>();
        while (keys.hasMoreElements()) {
            String key = keys.nextElement();
            list.add(new StartDicData(key, key));
        }
        return list;
    }

    public StartBasePlatformService getPlatformService(String platformType) {
        return getPlatformService(platformType, true);
    }

    public StartBasePlatformService getPlatformService(String platformType, boolean throwEx) {
        if (!map.containsKey(platformType)) {
            if (throwEx) {
                throw new RuntimeException("未找到指定第三方平台：" + platformType);
            }
            return null;
        }
        return map.get(platformType);
    }

    /**
     * 平台验证token
     *
     * @param platformType
     * @param appId
     * @return
     */
    public Object platformVerifyToken(String platformType, String appId) {
        StartBasePlatformService platformService = getPlatformService(platformType);
        return platformService.platformVerifyToken(appId);
    }

    /**
     * 用户绑定其他平台
     *
     * @param currentUser
     * @param platformType
     * @param appId
     * @param platformOpenId
     */
    public void bindOtherPlatform(BaseUserDetails currentUser, String platformType, String appId, String platformOpenId) {
        StartBasePlatformService platformService = getPlatformService(platformType);
        if (!platformService.hasAppId(appId)) {
            throw new RuntimeException("未在" + platformType + "平台中找到appId为：" + appId + "的配置");
        }
        StartPlatformFans platformFans = startPlatformFansService.getFansByOpenId(platformType, appId, platformOpenId);
        if (platformFans == null) {
            throw new StartBusException("未找到第三方平台用户信息");
        }
        if (StringUtils.isNotBlank(platformFans.getPlatformUserId())) {
            if (!currentUser.getUserId().equals(platformFans.getPlatformUserId())) {
                throw new StartBusException("该账号已被其他账号绑定");
            }
            return;
        }
        platformFans.setPlatformUserId(currentUser.getUserId());
        startPlatformFansService.updateById(platformFans);
    }


    /**
     * 获取用户信息
     *
     * @param platformType
     * @param appId
     * @param code
     * @return
     */
    public StartPlatformFansDetail getUserInfoByPlatformCode(String platformType, String appId, String code, JSONObject prop) {
        StartBasePlatformService platformService = getPlatformService(platformType);
        if (!platformService.hasAppId(appId)) {
            throw new RuntimeException("未在" + platformType + "平台中找到appId为：" + appId + "的配置");
        }
        return platformService.getUserInfoByPlatformCode(appId, code, prop);
    }


    public String login(String platformType, String appId, StartPlatformUserLoginModel loginModel) {
        StartBasePlatformService platformService = getPlatformService(platformType);
        if (!platformService.hasAppId(appId)) {
            throw new RuntimeException("未在" + platformType + "平台中找到appId为：" + appId + "的配置");
        }
        if (StringUtils.isAllBlank(loginModel.getLoginType())) {
            loginModel.setLoginType("username");
        }
        StartPlatformUserEntity userEntity;
        switch (loginModel.getLoginType()) {
            case "username":
                if (StringUtils.isAllBlank(loginModel.getUserName())) {
                    throw new StartBusException("请输入用户名");
                }
                if (StringUtils.isAllBlank(loginModel.getUserName())) {
                    throw new StartBusException("请输入密码");
                }
                userEntity = startPlatformUserService.getByUserName(loginModel.getUserName());
                if (userEntity == null) {
                    throw new StartBusException("用户名或密码不正确");
                }
                if (StringUtils.isAllBlank(userEntity.getUserPwd())) {
                    throw new StartBusException("请重置密码后在登录");
                }
                return login(userEntity, loginModel.getPassword());
            case "phone":
                if (StringUtils.isAllBlank(loginModel.getUserName())) {
                    throw new StartBusException("请输入您的手机号");
                }
                if (StringUtils.isAllBlank(loginModel.getUserName())) {
                    throw new StartBusException("请输入登您的录密码");
                }
                userEntity = startPlatformUserService.getByUserName(loginModel.getUserName());
                if (userEntity == null) {
                    throw new StartBusException("用户名或密码不正确");
                }
                if (StringUtils.isAllBlank(userEntity.getUserPwd())) {
                    throw new StartBusException("请重置密码后在登录");
                }
                return login(userEntity, loginModel.getPassword());
            default:
                throw new StartBusException("未知登录方式：" + loginModel.getLoginType());
        }

    }
}
